home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / midi / gfft.lha / gfft-2.03 / source / gfft-2.03-source.lha / format.c < prev    next >
C/C++ Source or Header  |  1996-01-02  |  15KB  |  574 lines

  1. /***************************************************************************
  2.  *          Copyright (C) 1994  Charles P. Peterson                  *
  3.  *         4007 Enchanted Sun, San Antonio, Texas 78244-1254             *
  4.  *              Email: Charles_P_Peterson@fcircus.sat.tx.us                *
  5.  *                                                                         *
  6.  *          This is free software with NO WARRANTY.                  *
  7.  *          See gfft.c, or run program itself, for details.              *
  8.  *              Support is available for a fee.                      *
  9.  ***************************************************************************
  10.  *
  11.  * Program:     gfft--General FFT analysis
  12.  * File:        format.c
  13.  * Purpose:     parse formatted files
  14.  * Author:      Charles Peterson (CPP)
  15.  * History:     18-October-1993 CPP; Created.
  16.  * Comment:     Thanks to Guido van Rossum for SOX and David Champion
  17.  *                for OmniPlay, from which much was learned.
  18.  *              Thanks to Malcolm Slaney and Ken Turkowski for
  19.  *                ConvertFromIeeeExtended, from which much was learned.
  20.  *              However, this is an original implementation, containing
  21.  *                no previously copyrighted code.
  22.  */
  23.  
  24. #include <math.h>
  25. #include <stdio.h>
  26. #include "gfft.h"
  27. #include "settings.h"
  28. #include "format.h"
  29.  
  30. #define NO_ERROR FALSE
  31. #define CORRUPT TRUE
  32. #define UNAVAIL_COMPRESSION 2
  33.  
  34. static unsigned long offset = 0;  /* Running offset pointer used here */
  35.  
  36. /*
  37.  * Static function declarations
  38.  */
  39. static void read_form_format (void);  /* Includes 8SVX, AIFF, AIFC types */
  40. static void read_8svx_format (long form_cksize);
  41. static int read_vhdr (ULONG form_cksize, struct ChunkHeader chunk_h);
  42. static void read_aiff_format (long form_cksize);
  43. static int read_comm_aiff (ULONG form_cksize, struct ChunkHeader chunk_h);
  44. static void read_aifc_format (long form_cksize);
  45. static int read_comm_aifc (ULONG form_cksize, struct ChunkHeader chunk_h);
  46. static double double_from_extended (UBYTE *extended);
  47. static void read_avr_format (void);
  48.  
  49. void reset_format (void)
  50. {
  51. /*
  52.  * Reset Global Format Info
  53.  */
  54.     FileFormat = UNFORMATTED;
  55.     FileFormatOK = FALSE;
  56.     FileRate = AUTO_RATE;
  57.     FileDataOffset = 0;
  58.     FileFrames = 0;
  59.     FileVolume = 1.0L;
  60.     FileOctaves = 1;
  61.     FileChannels = 1;
  62.     FileOneShotHiFrames = 0;
  63.     FileRepeatHiFrames = 0;
  64. }
  65.  
  66. void read_format (void)
  67. {
  68.     ID format_id;
  69.     int format = UNFORMATTED;
  70.  
  71.     reset_format();
  72.  
  73.     if (fread (&format_id, sizeof format_id, 1, ReadPtr))
  74.     {
  75.     offset = sizeof format_id;  /* This is where offset count begins */
  76.     switch (format_id)
  77.     {
  78.     case ID_FORM:             /* IFF 8SVX, AIFF, and AIFC */
  79.         format = ID_FORM;  /* Clarified later */
  80.         break;
  81.     case ID_RIFF:
  82.         format = ID_RIFF;
  83.         break;
  84.     case ID_VOCH:
  85.         format = ID_VOCH;
  86.         break;
  87.     case ID_AVR:
  88.         format = ID_AVR;
  89.         break;
  90.     }
  91.     }
  92.     if (format != UNFORMATTED)
  93.     {
  94.     if (IgnoreFormat)
  95.     {
  96.         error_message (FILE_FORMAT_IGNORED);
  97.         return;
  98.     }
  99.     Rate = AUTO_RATE;    /* override must be forced afterwards */
  100.     }
  101.     FileFormat = format;
  102.     switch (format)
  103.     {
  104.     case ID_FORM:
  105.     read_form_format ();
  106.     break;
  107.     case ID_AVR:
  108.     read_avr_format ();
  109.     break;
  110.     case UNFORMATTED:
  111.     break;
  112.     default:
  113.     error_message (UNSUPPORTED_FORMAT);
  114.     FileFormatOK = FALSE;
  115.     }
  116. }
  117.  
  118. static void read_form_format (void)  /* Includes 8SVX, AIFF, AIFC types */
  119. {
  120.     ULONG form_cksize;
  121.     ID form_type;
  122.  
  123.     if (fread (&form_cksize, sizeof form_cksize, 1, ReadPtr) &&
  124.         fread (&form_type, sizeof form_type, 1, ReadPtr))
  125.     {
  126.     offset += sizeof form_cksize + sizeof form_type;
  127.     switch (form_type)
  128.     {
  129.     case ID_8SVX:
  130.         FileFormat = ID_8SVX;
  131.         read_8svx_format (form_cksize);
  132.         break;
  133.     case ID_AIFF:
  134.         FileFormat = ID_AIFF;
  135.         read_aiff_format (form_cksize);
  136.         break;
  137.     case ID_AIFC:
  138.         FileFormat = ID_AIFC;
  139.         read_aifc_format (form_cksize);
  140.         break;
  141.     default:
  142.         error_message (UNSUPPORTED_FORMAT);
  143.         break;
  144.     }
  145.     }
  146.     else
  147.     {
  148.     error_message (CORRUPT_IFF); /* Missing cksize and/or type! */
  149.     }
  150. }
  151.  
  152. static void read_8svx_format (long form_cksize)
  153. /*
  154.  * Chunks are allowed to be in any order.
  155.  * But, a fast and lazy approach is taken to validation:
  156.  *   Chunks looked for: VHDR and BODY
  157.  *     (Once those two have been found, and VHDR read, I exit.)
  158.  *   BODY chunk isn't read (so premature file end must be detected later)
  159.  *   BODY chunk is fseek'd over only if VHDR hasn't been found yet.
  160.  *   form_cksize isn't actually checked
  161.  */
  162. {
  163.     int error = NO_ERROR;
  164.     struct ChunkHeader chunk_h;
  165.     ULONG skip_bytes;
  166.     BOOLEAN vhdr_found = FALSE;
  167.     BOOLEAN body_found = FALSE;
  168.  
  169.     InputFormat.bits = 8; /* True of all 8SVX */
  170.     InputFormat.zero = 0; /* Ditto */
  171.  
  172.     while (fread (&chunk_h, sizeof chunk_h, 1, ReadPtr))
  173.     {
  174.     offset += sizeof chunk_h;
  175.     switch (chunk_h.ckID)
  176.     {
  177.     case ID_VHDR:
  178.         vhdr_found = TRUE;
  179.         error = read_vhdr (form_cksize, chunk_h);
  180.         offset += WordAlign (chunk_h.ckSize);
  181.         break;
  182.     case ID_BODY:
  183.         body_found = TRUE;
  184.         FileDataOffset = offset;
  185.         if (!vhdr_found && !error)  /* If still looking for VHDR */
  186.         {
  187.         skip_bytes = WordAlign (chunk_h.ckSize);
  188.         error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
  189.         offset += skip_bytes;
  190.         }
  191.         break;
  192.     default:
  193.         skip_bytes = WordAlign (chunk_h.ckSize);
  194.         error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
  195.         offset += skip_bytes;
  196.         break;
  197.     }
  198.     if (error || (vhdr_found && body_found))
  199.     {
  200.         break;
  201.     }
  202.     }
  203.     if (!vhdr_found || !body_found || error)
  204.     {
  205.     if (error <= CORRUPT)  /* Higher errors reported elsewhere */
  206.     {
  207.         error_message (CORRUPT_IFF);
  208.     }
  209.     }
  210.     else
  211.     {
  212.     FileFormatOK = TRUE;
  213.     }
  214. }
  215.  
  216. static int read_vhdr (ULONG form_cksize, struct ChunkHeader chunk_h)
  217. {
  218.     int error = CORRUPT; /* defaulted if chunk not completely read */
  219.     struct VHDR vhdr;
  220.     ULONG skip_bytes;
  221.  
  222.     if (chunk_h.ckSize < sizeof vhdr)
  223.     {
  224.     return CORRUPT; /* Error! Pre '85 or corrupt! */
  225.     }
  226.     if (fread (&vhdr, sizeof vhdr, 1, ReadPtr))
  227.     {
  228.     FileRate = vhdr.samplesPerSec;
  229.     if (vhdr.sCompression)
  230.     {
  231.         error_message (COMPRESSION_NOT_SUPPORTED);
  232.         return UNAVAIL_COMPRESSION;
  233.     }
  234.     FileVolume = vhdr.volume / 65536.0L;
  235.     FileOctaves = vhdr.ctOctave;
  236.     FileOneShotHiFrames = vhdr.oneShotHiSamples;
  237.     FileRepeatHiFrames = vhdr.repeatHiSamples;
  238.     FileFrames = FileOneShotHiFrames + FileRepeatHiFrames;
  239.  
  240.     error = NO_ERROR;
  241.     if (skip_bytes = WordAlign (chunk_h.ckSize - sizeof vhdr)) /* = */
  242.     {
  243.         error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
  244.         offset += skip_bytes;
  245.     }
  246.     }
  247.     return error;
  248. }
  249.  
  250. static void read_aiff_format (long form_cksize)
  251. /*
  252.  * Chunks are allowed to be in any order.
  253.  * But, a fast and lazy approach is taken to validation:
  254.  *   Chunks looked for: Common (COMM) and Sound Data (SSND)
  255.  *     (Note: COMM here is different from the AIFC version.)
  256.  *     (Once those two have been found, and COMM read, I exit.)
  257.  *   SSND chunk isn't read (so premature file end must be detected later)
  258.  *   SSND chunk is fseek'd over only if VHDR hasn't been found yet.
  259.  *   form_cksize isn't actually checked
  260.  */
  261. {
  262.     ULONG skip_bytes;
  263.     int error = NO_ERROR;
  264.     struct ChunkHeader chunk_h;
  265.     struct SoundDataChunkInfo sdci;
  266.     BOOLEAN ssnd_found = FALSE;
  267.     BOOLEAN comm_found = FALSE;
  268.  
  269.     while (fread (&chunk_h, sizeof chunk_h, 1, ReadPtr))
  270.     {
  271.     offset += sizeof chunk_h;
  272.     switch (chunk_h.ckID)
  273.     {
  274.     case ID_COMM:
  275.         comm_found = TRUE;
  276.         error = read_comm_aiff (form_cksize, chunk_h);
  277.         offset += WordAlign (chunk_h.ckSize);
  278.         break;
  279.     case ID_SSND:
  280.         ssnd_found = TRUE;
  281.         error = !fread (&sdci, sizeof sdci, 1, ReadPtr);
  282.         offset += sizeof sdci;
  283.         FileDataOffset = offset + sdci.offset;
  284.         if (!comm_found && !error)
  285.         {
  286.         skip_bytes = WordAlign (chunk_h.ckSize - sizeof sdci);
  287.         error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
  288.         offset += skip_bytes;
  289.         }
  290.         break;
  291.     default:
  292.         skip_bytes = WordAlign (chunk_h.ckSize);
  293.         error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
  294.         offset += skip_bytes;
  295.         break;
  296.     }
  297.     if (error || (comm_found && ssnd_found))
  298.     {
  299.         break;
  300.     }
  301.     }
  302.     if (!comm_found || !ssnd_found || error)
  303.     {
  304.     if (error <= CORRUPT) /* Higher errors reported elsewhere */
  305.     {
  306.         error_message (CORRUPT_AIFF);
  307.     }
  308.     }
  309.     else
  310.     {
  311.     FileFormatOK = TRUE;
  312.     }
  313. }
  314.  
  315. static int read_comm_aiff (ULONG form_cksize, struct ChunkHeader chunk_h)
  316. {
  317.     int error = CORRUPT; /* defaulted if chunk not completely read */
  318.     int skip_bytes;
  319.     struct CommAiff comm;
  320.  
  321.     if (chunk_h.ckSize < sizeof comm)
  322.     {
  323.     return CORRUPT;  /* Error...corrupt or unsupported AIFF format */
  324.     }
  325.     if (fread (&comm, sizeof comm, 1, ReadPtr))
  326.     {
  327.     FileChannels = comm.numChannels;
  328.     FileFrames = comm.numSampleFrames;
  329.     InputFormat.bits = comm.sampleSize;
  330.     InputFormat.zero = 0;
  331.     FileRate = double_from_extended (comm.sampleRate);
  332.  
  333.     error = NO_ERROR;
  334.     if (skip_bytes = WordAlign (chunk_h.ckSize - sizeof comm)) /* = */
  335.     {
  336.         error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
  337.         offset += skip_bytes;
  338.     }
  339.     }
  340.     return error;
  341. }
  342.  
  343. static void read_aifc_format (long form_cksize)
  344. /*
  345.  * Chunks are allowed to be in any order.
  346.  * But, a fast and lazy approach is taken to validation:
  347.  *   Chunks looked for: COMM and SSND
  348.  *     (Once those two have been found, and COMM read, I exit.)
  349.  *   SSND chunk isn't read (so premature file end must be detected later)
  350.  *   SSND chunk is fseek'd over only if VHDR hasn't been found yet.
  351.  *   form_cksize isn't actually checked
  352.  */
  353. {
  354.     ULONG skip_bytes;
  355.     int error = NO_ERROR;
  356.     struct ChunkHeader chunk_h;
  357.     struct SoundDataChunkInfo sdci;
  358.     BOOLEAN ssnd_found = FALSE;
  359.     BOOLEAN comm_found = FALSE;
  360.  
  361.     while (fread (&chunk_h, sizeof chunk_h, 1, ReadPtr))
  362.     {
  363.     offset += sizeof chunk_h;
  364.     switch (chunk_h.ckID)
  365.     {
  366.     case ID_COMM:
  367.         comm_found = TRUE;
  368.         error = read_comm_aifc (form_cksize, chunk_h);
  369.         offset += WordAlign (chunk_h.ckSize);
  370.         break;
  371.     case ID_SSND:
  372.         ssnd_found = TRUE;
  373.         error = !fread (&sdci, sizeof sdci, 1, ReadPtr);
  374.         offset += sizeof sdci;
  375.         FileDataOffset = offset + sdci.offset;
  376.         if (!comm_found && !error)
  377.         {
  378.         skip_bytes = WordAlign (chunk_h.ckSize - sizeof sdci);
  379.         error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
  380.         offset += skip_bytes;
  381.         }
  382.         break;
  383.     default:
  384.         skip_bytes = WordAlign (chunk_h.ckSize);
  385.         error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
  386.         offset += skip_bytes;
  387.         break;
  388.     }
  389.     if (error || (comm_found && ssnd_found))
  390.     {
  391.         break;
  392.     }
  393.     }
  394.     if (!comm_found || !ssnd_found || error)
  395.     {
  396.     if (error <= CORRUPT)
  397.     {
  398.         error_message (CORRUPT_AIFC);
  399.     }
  400.     }
  401.     else
  402.     {
  403.     FileFormatOK = TRUE;
  404.     }
  405. }
  406.  
  407. static int read_comm_aifc (ULONG form_cksize, struct ChunkHeader chunk_h)
  408. {
  409.     int error = CORRUPT;  /* Defaulted if chunk not read */
  410.     int skip_bytes;
  411.     struct CommAifc comm;
  412.  
  413.     if (chunk_h.ckSize < sizeof comm)
  414.     {
  415.     return CORRUPT;  /* Error...corrupt or unsupported AIFF format */
  416.     }
  417.     if (fread (&comm, sizeof comm, 1, ReadPtr))
  418.     {
  419.     FileChannels = comm.numChannels;
  420.     FileFrames = comm.numSampleFrames;
  421.     InputFormat.bits = comm.sampleSize;
  422.     InputFormat.zero = 0;
  423.     FileRate = double_from_extended (comm.sampleRate);
  424.     if (comm.compressionType != ID_NONE)
  425.     {
  426.         error_message (COMPRESSION_NOT_SUPPORTED);
  427.         return UNAVAIL_COMPRESSION;
  428.     }
  429.  
  430.     error = NO_ERROR;
  431.     if (skip_bytes = WordAlign (chunk_h.ckSize - sizeof comm)) /* = */
  432.     {
  433.         error = !!fseek (ReadPtr, skip_bytes, SEEK_CUR);
  434.         offset += skip_bytes;
  435.     }
  436.     }
  437.     return error;
  438. }
  439.  
  440.  
  441. /*
  442.  * The following is based on ideas from ConvertFromIeeeExtended
  443.  * by Malcolm Slaney and Ken Turkowski.  However, since that was
  444.  * copyright by Apple Computer, Inc., I have prepared an original
  445.  * implementation here.
  446.  *
  447.  * Note: NaN's and infinities are converted to HUGE_VAL.  This is
  448.  * not very nice for NaN's.
  449.  *
  450.  * WARNING!  THIS HASN'T BEEN WELL TESTED, SO I WOULDN'T USE THIS FOR
  451.  * OTHER OR SERIOUS PURPOSES OR ON OTHER ARCHITECTURES.
  452.  */
  453.  
  454. #define UPPER_EXP_MASK 0x7F
  455. #define SIGN_MASK 0x80
  456.  
  457. #define INFINITE_EXPONENT 0x7FFF
  458.  
  459. #define HI_E_OFF 16414 /* (16383 + 31) */
  460. #define LO_E_OFF 16446 /* (16383 + 31 + 32) */
  461. #define U_TO_F(u) (((double) ((long) ((u)-2147483647L-1))) + 2147483648.0)
  462.  
  463. static double double_from_extended (UBYTE *extended)
  464. {
  465.     double dval;
  466.     ULONG high_mantissa;
  467.     ULONG low_mantissa;
  468.     int exponent;
  469.  
  470.     exponent = ((extended[0] & UPPER_EXP_MASK) << 8) | extended[1];
  471.  
  472.     high_mantissa = ((ULONG) (extended[2] << 24)) |
  473.                     ((ULONG) (extended[3] << 16)) |
  474.             ((ULONG) (extended[4] << 8))  |
  475.             (ULONG) extended[5];
  476.  
  477.     low_mantissa =  ((ULONG) (extended[6] << 24)) |
  478.                     ((ULONG) (extended[7] << 16)) |
  479.             ((ULONG) (extended[8] << 8))  |
  480.             (ULONG) extended[9];
  481.  
  482.     if (exponent == 0 && high_mantissa == 0 && low_mantissa == 0)
  483.     {
  484.         dval = 0;
  485.     }
  486.     else 
  487.     {
  488.     if (exponent == INFINITE_EXPONENT)  /* Infinity or NaN */
  489.     {
  490.         dval = HUGE_VAL;  /* from ANSI C math.h */
  491.     }
  492.     else
  493.     {
  494.         dval = ldexp ( U_TO_F (high_mantissa), exponent - HI_E_OFF) +
  495.                ldexp ( U_TO_F (low_mantissa),  exponent - LO_E_OFF);
  496.     }
  497.     if (extended[0] & SIGN_MASK)
  498.     {
  499.         dval  = (-dval);
  500.     }
  501.     }
  502.     return dval;
  503. }
  504.  
  505. static void read_avr_format (void)
  506. {
  507.     struct AVRH avrh;
  508.  
  509.     if (!fread (&avrh, sizeof avrh, 1, ReadPtr))
  510.     {
  511.     error_message (CORRUPT_AVR);
  512.     }
  513.     else
  514.     {
  515.     FileFormatOK = TRUE;
  516.     FileDataOffset = sizeof (ID) + sizeof (struct AVRH);
  517.  
  518.     if (avrh.mono == 0)
  519.     {
  520.         FileChannels = 1;
  521.     }
  522.     else if (avrh.mono == -1)
  523.     {
  524.         FileChannels = 2;
  525.     }
  526.     else
  527.     {
  528.         error_message (CORRUPT_AVR);
  529.         FileFormatOK = FALSE;
  530.     }
  531.  
  532.     InputFormat.bits = avrh.rez;
  533.     if (InputFormat.bits > 16 || InputFormat.bits < 0)
  534.     {
  535.         error_message (CORRUPT_AVR);
  536.         FileFormatOK = FALSE;
  537.     }
  538.  
  539.     if (avrh.sign == -1)
  540.     {
  541.         InputFormat.zero = 0;
  542.     }
  543.     else if (avrh.sign == 0)
  544.     {
  545.         int sample_width = (InputFormat.bits > 8) ? 16 : 8;
  546.         InputFormat.zero = ((unsigned long) 0xffffffff >> 
  547.                 (33 - sample_width)) + (unsigned long) 1;
  548.     }
  549.     else
  550.     {
  551.         error_message (CORRUPT_AVR);
  552.         FileFormatOK = FALSE;
  553.     }
  554.  
  555.     FileRate = avrh.rate & 0xFFFFFF;  /* I don't understand why */
  556. /*
  557.  * Maybe FF in upper bits MEANS number is an integer, no FF means float
  558.  * But, my docs didn't say this
  559.  */
  560.     FileFrames = avrh.size;
  561.     if (FileFrames < 0)
  562.     {
  563.         error_message (CORRUPT_AVR);
  564.         FileFormatOK = FALSE;
  565.     }
  566.  
  567.     if (avrh.res2)
  568.     {
  569.         error_message (COMPRESSION_NOT_SUPPORTED);
  570.         FileFormatOK = FALSE;
  571.     }
  572.     }
  573. }
  574.